/*************************************************************************
	> File Name: cancel_subcontract.c
	> Author: 
	> Mail: 
	> Created Time: 2015年01月19日 星期一 22时52分32秒
 ************************************************************************/
#include<pthread.h>
#include"errors.h"

#define THREADS  5

typedef struct team_tag{
    int         join_i;
    pthread_t   workers[THREADS];
} team_t;

void *worker_routine(void *arg){
    int counter;

    for(counter = 0;;counter++){
        if((counter % 1000) == 0){
            pthread_testcancel();
        }
    }
    printf("exit worker routine\n"); // never print
}

void cleanup(void *arg){
    team_t * team = (team_t *) arg;
    int count ,status;

    for(count = team->join_i; count < THREADS; count++){
        status = pthread_cancel(team->workers[count]);
        if(status) err_abort(status, "cancel worker");
        
        status = pthread_detach(team->workers[count]);
        if(status) err_abort(status, "Detach worker");

        printf("Cleanup : canceled %d\n", count);
    }
}

void * thread_routine(void *arg){
    team_t team;
    int count;
    void * result;
    int status;

    for(count = 0;count < THREADS;count++){
        status = pthread_create(&team.workers[count],NULL,worker_routine,NULL);
        if(status) err_abort(status,"Create worker");
        printf("create worker %d \n",count);
    }
    pthread_cleanup_push(cleanup,(void*)&team);

    for(team.join_i = 0;team.join_i < THREADS; team.join_i++){
        status = pthread_join(team.workers[team.join_i], &result);
        if(status) err_abort(status,"Join worker");
    }
    pthread_cleanup_pop(0);
    printf("exit thread_routine\n");
    return NULL;
}

int main(int argc ,char * argv[]){
    pthread_t thread_id;
    int status;

    status = pthread_create(&thread_id,NULL,thread_routine,NULL);
    if(status) err_abort(status,"Create team");
    printf("create team thread\n");

    sleep(5);
    printf("Cancelling ...\n");

    pthread_cancel(thread_id);

    pthread_join(thread_id,NULL);

    return 0;
}
